home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
LIBRARY
/
FUTILS
/
FWIN.DOC
< prev
next >
Wrap
Text File
|
1989-02-21
|
11KB
|
268 lines
/\ RKCP /\
\/ RKCP \/
********************************************************************
************************* FWIN by Rex Kerr *************************
************************ Copyright (C) 1989 ************************
********************************************************************
This is a unit designed to give simple windowing capabilities to
any program. It uses FWRITE, so it is very fast, but it also
causes snow on snowy CGAs. It also won't autodetect EGA or VGA
cards (another weakness of FWRITE). On top of all that, if you
call windows in circles (i.e. you call window #1, then #2, #3, #1,
#2, etc.) and then delete one, the image will be left on the screen,
even though the window itself is gone. By now, I've made it sound
horrible enough for no-one to want to use it. But it is very fast,
and it works very well at popping up a window and then throwing it
away after you have used it.
FWIN is implemented using a circular doubly linked list. Therefore,
you can call up any window at any time. By the way, it uses the
standard DOS and CRT units as well as my FWRITE unit.
***
FWIN's window structure is declared like this:
type winptr = ^winrec;
winrec = record
x,y,w,h : byte; { The borders of the window }
cx,cy : byte; { The position of the cursor }
id : byte; { Each window has a unique ID
number }
wscreen : vram_scrbuf; { This is where the
saved window goes }
up,dn : winptr; { Pointers to the windows after
and before this one }
border : boolean; { Is there a border or not? }
end;
The only visible variable in the FWIN unit is the "base" of the
window list. The current window is always one up from this.
var windowset : winptr;
***
GetVram(var Scrn : Vram_ScrBuf);
Since FWIN often gets the whole screen, it calls this, which calls
the GetVramSec procedure in FWRITE. It is equivalent to
GetVramSec(scrn,1,1,80,25,1,1);
***
PutVram(Scrn : Vram_ScrBuf);
This puts all of Vram_ScrBuf on the screen. It simply calls FWRITE
like this: PutVramSec(Scrn,1,1,80,25,1,1);
It just saves some typing on your part.
***
Bordermaker(a,b,c,d,e,f : byte) : string;
This turns bytes a,b,c,d,e,f into characters and places them in a
string. It is useful for making window borders with ASCII values
above 126 or below 32.
***
SetTextAttr(attr : byte);
This sets the current writing attribute for Turbo Pascal's Write
and WriteLn.
***
GetXY(var x,y : byte);
This calls TP5's WhereX and WhereY. It's just a time-saver.
***
CreateWindow(id : byte; x,y,w,h : byte; wattr,battr : byte;
st,border : string);
Wow! What does this do?
The borders of the window are x,y,w,h. Border is either an empty
string (for no border) or the 6 chars used in the border. This is
what the characters are used for:
#1 : top left corner #2: top right corner
#3 : bottom left corner #4: bottom right corner
#5 : horizontal lines #6: vertical lines
St is the string used for the "title" of the window. It is placed
centered in the top line of the border. If there is no border, st
is not used. Batr is the attribute used for the border, and Watr
is the attribute used for the main text. While we're at it, here's
at table showing the which values give which colors:
COLOR FOREGROUND BACKGROUND HI-INTENSITY FOREGROUND
Black 0 0 8 (Gray)
Blue 1 16 9 (Light blue)
Green 2 32 10 (Light green)
Cyan 3 48 11 (Light cyan)
Red 4 64 12 (Pink)
Magenta 5 80 13 (Light magenta)
Brown 6 96 14 (Yellow)
White 7 112 15 (Hi-intesity white)
To get the desire attribute, add the foreground color to the
background color. For example, to get white on a black background,
the attribute is 7. For pink on a magenta background, the
attribute is 92. To make the foreground characters blink, add 128
to the total.
And finally, ID is the window's unique identification number. You
use it in most of the other window routines. If you specify the ID
number of an already existing window, nothing will happen.
***
RemoveWindow(id : byte);
This removes the window (specified by ID) from the linked list. It
doesn't, however, do anything about the image on the screen. If you
specify an ID that is non-existant, nothing will happen. You can
check to see if a window exists or not using ExistWindow.
***
GotoWindow(id : byte);
This gets the specified window and puts it at the beginning of the
linked list and updates the screen. If a non-existant ID is called,
nothing wil happen.
***
PopWindow;
This removes the current window from the linked list and the screen.
The window behind the current window now becomes the current window.
***
ExistWindow(id : byte) : boolean;
This returns true if a window with the specified ID exists.
Otherwise, it returns false.
***
Okay, that's everything. But I'd like to write a few extra routines
here. With createwindow, one of the problems is it's a bit hard to
find out which ID numbers are already existing. You could call
existwindow from 1 until you get a false, but if you have a lot of
windows, that could take a few lines that you might not want. So
let's write a function that returns the first unused ID.
function EmptyWindowID : byte;
var temptr : winptr; { We need a pointer to walk through the list }
i,j : byte; { Variables for storing the free ID }
begin
i := 0; j := 0; { Initialize the variables }
while (i <> 0) do { i gets set to the free ID #. It will }
begin { remain 0 until then. }
inc(j); { j is the counter for possible open windows }
temptr := windowset^.up; { temptr is pointing to the
current window }
while (temptr <> windowset) and (temptr^.id <> j) do
begin { If temptr's ID = j or temptr has cirled the list, STOP }
nptr := nptr^.up; { Go up to the next window }
end;
if nptr = windowset then i := j; { If temptr has circled, }
end; { that ID is free, so set i }
EmptyWindowID := i; { give the function the result }
end;
What this does is it circles through the linked list to see if
any of the windows have an ID of 1. If none do, i is set to one.
Otherwise, the same thing is done for 2 and 3 and 4 etc. until
a "free" ID is found. Then the function is set to the value of i
(the free ID number).
That wasn't so hard. Now, let's do something else. How about this:
The screen has gotten rather cluttered up, and you want to clean it
up. How do you do that? Why don't we write a procedure to do that
for us.
procedure CleanUpScreen;
var temptr : winptr;
i : byte;
begin
i := EmptyWindowID;
createwindow(i,1,1,80,25,7,7,'','');
temptr := windowset^.dn;
while temptr <> windowset do
begin
if temptr^.id <> i then gotowindow(temptr^.id);
end;
removewindow(i);
end;
I didn't include any comments on purpose. I'm going to let you
figure out what each line does. That is, in my opinion, the second
best way to learn how to program (assuming you know the basics). I
think the best way is just to program and program and program
whatever yourself. Most of my programming so far has been in the
realm of useless. I have scores of tiny programs that do everything
from create random beeps to copy one file half as fast as DOS
would. But I have gotten lots of experience from that, and now I
can quickly whip up a simple program when I need it. One example
is this: I had a list of books read and how many pages were in
each one. I was supposed to add the pages to get the total and
check to make sure there was only one entry for each book. So
in about fifteen or twenty minutes, I had written a program that
did just that. Then, I spent another fifteen minutes entering the
list into the computer (the list was on paper). So, in roughly
35 minutes, I did a job which, without any programming, would have
taken maybe 40 minutes. Big deal. I saved 5 minutes. But now I
have the program, and it I'm most likely going to have to do that
again, so overall, I could end up saving myself hours. So now, all
that experience with writing all those tiny programs is starting to
pay off.
Whoa! I thought I was supposed to be writing documentation for
FWIN! Okay, back to that now.
I will give you a bit of help in understanding what the
CleanUpScreen procedure does. First it calls EmptyWindowID to find
an unused ID. Then it creates a big blank window to clear the
screen. After that, it starts at the back of the list, calling
each window until it arrives at the "base" to rebuild the screen.
Along the way, it makes sure to skip the blank window, so the work
won't be wasted. Then, after the screen has been cleared and
updated, it removes the blank window from memory, and quits.
I also have a second windowing unit, XWIN. XWIN is slower than
FWIN is, but it doesn't have the "junk" problem. XWIN's
popwindows can be up to 10 times slower than FWIN's, but with
XWIN you never need the CleanUpScreen procedure. Actually, if
FWIN calls CleanUpScreen after each popwindow to make sure the
screen doesn't have any inactive windows, XWIN is much faster. Also,
FWIN takes 4 kbytes of heap for each window, whether the window is
5*4 or 80*25. XWIN takes up a 22 bytes plus the amount of memory
required to hold just the window. Here's a formula to calculate
that amount of memory:
mem_required := (window_width * window_height) * 2;
But you don't have to worry about calculating the memory; XWIN does
it for you.
I prefer using XWIN, but FWIN can still be useful.
If you think I've left anything out, or if anything is unclear,
please contact me via Compuserve, using either EasyPlex or the
TP5 messages section of BPROGA.
Rex Kerr 71550,3147
/\ RKCP /\
\/ RKCP \/